//
//  YSSpreadSheetView.swift
//  YSSpreadSheetView
//
//  Created by 万孟超 on 2023/5/5.
//

import UIKit

private func floatPixel(with value: CGFloat) -> CGFloat {
    return value / UIScreen.main.scale * max(UIScreen.main.scale - 1, 1)
}

fileprivate extension YSSpreadSheetSubView {
    /// 边框线的位置
    enum CellPosition {
        case unkown  // 未知
        case leftTop
        case leftTopRight
        case leftTopBottom
        case leftTopRightBottom
    }
    
    /// 需要添加边框的位置
    struct BorderSide: OptionSet {
        let rawValue: Int
        static let left = BorderSide(rawValue: 1)
        static let right = BorderSide(rawValue: 1 << 1)
        static let top = BorderSide(rawValue: 1 << 2)
        static let bottom = BorderSide(rawValue: 1 << 3)
    }
}

open class YSSpreadSheetSubView: UIView {
    
    // MARK: Public
    
    public var isHighLight: Bool = false {
        didSet {
            setCellHighLight(isHighLight)
        }
    }
    
    public var isSelected: Bool = false
    
    public private(set) lazy var sheetTitleLabel: UILabel = {
        let lb = UILabel()
        lb.font = UIFont.systemFont(ofSize: 14)
        lb.textColor = .black
        lb.backgroundColor = .clear
        lb.translatesAutoresizingMaskIntoConstraints = false
        addSubview(lb)
        lb.topAnchor.constraint(equalTo: topAnchor, constant: 4).isActive = true
        lb.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 4).isActive = true
        lb.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -4).isActive = true
        lb.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -4).isActive = true
        return lb
    }()
    
    // MARK: fileprivate
    
    fileprivate var widthLayout: NSLayoutConstraint?
    
    fileprivate var cellDidHighLightBlock: ((YSSpreadSheetSubView, Bool) -> ())?
    
    /// 边框位置
    fileprivate var position: CellPosition = .unkown {
        didSet {
            drawCellBorder()
        }
    }
    
    fileprivate weak var viewTapDelegate: YSSpreadSheetViewDelegate? = nil
    
    /// 边框线宽度
    fileprivate var lineWidth: CGFloat = 0
    
    /// 边框线颜色
    fileprivate var lineColor: UIColor = .clear
    
    /// Cell的索引
    fileprivate var indexPath: IndexPath?
    
    // MARK: Private
    
    private lazy var tapGesture: UITapGestureRecognizer = {
        let tap = UITapGestureRecognizer(target: self, action: #selector(cellTapGestureAction))
        tap.numberOfTapsRequired = 1
        tap.delegate = self
        return tap
    }()
    
    private var tempBackColor: UIColor? = nil
    
    // MARK: Public Method
    
    override public init(frame: CGRect) {
        super.init(frame: frame)
        isUserInteractionEnabled = true
        addTapGesture()
    }
    
    init() {
        super.init(frame: .zero)
        isUserInteractionEnabled = true
        addTapGesture()
    }
    
    required public init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// MARK: YSSpreadSheetSubView私有方法
private extension YSSpreadSheetSubView {
    func addTapGesture() {
        addGestureRecognizer(tapGesture)
    }
    
    @objc func cellTapGestureAction() {
        if !isSelected {
            if viewTapDelegate!.spreadSheetView?(self, shouldSelectItemAt: indexPath!) ?? true {
                isSelected = true
            }
        }else{
            if viewTapDelegate!.spreadSheetView?(self, shouldDeselectItemAt: indexPath!) ?? true {
                isSelected = false
            }
        }
        
        if !isHighLight {
            if viewTapDelegate!.spreadSheetView?(self, shouldHighlightAt: indexPath!) ?? true {
                isHighLight = true
            }
        }else{
            if viewTapDelegate!.spreadSheetView?(self, shouldUnHighlightAt: indexPath!) ?? true {
                isHighLight = false
            }
        }
    }
    
    func setCellSelected(_ selected: Bool) {
        if selected {
            viewTapDelegate!.spreadSheetView?(self, didSelectItemAt: indexPath!)
        }else{
            viewTapDelegate!.spreadSheetView?(self, deselectItemAt: indexPath!)
        }
    }
    
    func setCellHighLight(_ highLight: Bool) {
        if highLight {
            tempBackColor = backgroundColor?.mutableCopy() as? UIColor
            viewTapDelegate!.spreadSheetView?(self, didHighlightAt: indexPath!)
            backgroundColor = UIColor(red: 65.0 / 255.0, green: 105.0 / 255.0, blue: 225.0 / 255.0, alpha: 0.2)
        }else{
            viewTapDelegate!.spreadSheetView?(self, didUnHighlightAt: indexPath!)
            backgroundColor = tempBackColor?.mutableCopy() as? UIColor
        }
        cellDidHighLightBlock?(self, highLight)
    }
    
    /// 绘制边框线
    func drawCellBorder() {
        switch position {
            case .leftTop:
                createBorderView(with: [.left, .top])
                break
            case .leftTopRight:
                createBorderView(with: [.top, .left, .right])
                break
            case .leftTopBottom:
                createBorderView(with: [.top, .left, .bottom])
                break
            case .leftTopRightBottom:
                createBorderView(with: [.top, .left, .right, .bottom])
                break
            default:
                break
        }
    }
    
    /// 创建边框线
    /// - Parameter side: 画线位置
    func createBorderView(with side: BorderSide) {
        if side.contains(.top) {
            let view = UIView()
            view.backgroundColor = lineColor
            view.translatesAutoresizingMaskIntoConstraints = false
            addSubview(view)
            view.topAnchor.constraint(equalTo: topAnchor).isActive = true
            view.leadingAnchor.constraint(equalTo: leadingAnchor, constant: floatPixel(with: lineWidth)).isActive = true
            view.trailingAnchor.constraint(equalTo: trailingAnchor, constant: floatPixel(with: lineWidth)).isActive = true
            view.heightAnchor.constraint(equalToConstant: floatPixel(with: lineWidth)).isActive = true
        }
        if side.contains(.left) {
            let view = UIView()
            view.backgroundColor = lineColor
            view.translatesAutoresizingMaskIntoConstraints = false
            addSubview(view)
            view.topAnchor.constraint(equalTo: topAnchor).isActive = true
            view.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
            view.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
            view.widthAnchor.constraint(equalToConstant: floatPixel(with: lineWidth)).isActive = true
        }
        if side.contains(.right) {
            let view = UIView()
            view.backgroundColor = lineColor
            view.translatesAutoresizingMaskIntoConstraints = false
            addSubview(view)
            view.topAnchor.constraint(equalTo: topAnchor).isActive = true
            view.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
            view.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
            view.widthAnchor.constraint(equalToConstant: floatPixel(with: lineWidth)).isActive = true
        }
        if side.contains(.bottom) {
            let view = UIView()
            view.backgroundColor = lineColor
            view.translatesAutoresizingMaskIntoConstraints = false
            addSubview(view)
            view.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
            view.leadingAnchor.constraint(equalTo: leadingAnchor, constant: floatPixel(with: lineWidth)).isActive = true
            view.trailingAnchor.constraint(equalTo: trailingAnchor, constant: floatPixel(with: lineWidth)).isActive = true
            view.heightAnchor.constraint(equalToConstant: floatPixel(with: lineWidth)).isActive = true
        }
    }
}

extension YSSpreadSheetSubView: UIGestureRecognizerDelegate {
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        return true
    }
}

open class YSSpreadSheetView: UIView {
    
    /// 表格代理
    public weak var delegate: YSSpreadSheetViewDelegate? = nil {
        didSet {
            scrollView.delegate = delegate
        }
    }
    
    /// 表格数据源
    public weak var dataSource: YSSpreadSheetViewDataSource? = nil
    
    /// 表格配置
    private var config = YSSpreadSheetViewConfig()
    
    /// 高亮的Cell
    private var highLightCellArray: [YSSpreadSheetSubView] = []
    
    /// 滑动背景
    private lazy var scrollView: UIScrollView = {
        let scrol = UIScrollView()
        scrol.translatesAutoresizingMaskIntoConstraints = false
        scrol.showsVerticalScrollIndicator = config.showsVerticalScrollIndicator
        scrol.showsHorizontalScrollIndicator = config.showsHorizontalScrollIndicator
        return scrol
    }()
    
    /// 初始化方法
    /// - Parameters:
    ///   - config: 表格配置
    ///   - delegate: 代理
    ///   - dataSource: 数据源
    public convenience init(config: YSSpreadSheetViewConfig = YSSpreadSheetViewConfig(), delegate: YSSpreadSheetViewDelegate? = nil, dataSource: YSSpreadSheetViewDataSource? = nil) {
        self.init()
        self.config = config
        self.delegate = delegate
        self.dataSource = dataSource
        translatesAutoresizingMaskIntoConstraints = false
        backgroundColor = config.sheetBackgroundColor
        initSubviews()
    }
    
    /// 获取Cell
    /// - Parameter indexPath: 索引
    /// - Returns: Cell
    public func cellforItem(at indexPath: IndexPath) -> YSSpreadSheetSubView? {
        return dataSource?.spreadSheetView(self, cellAt: indexPath)
    }
    
    /// 刷新
    public func reloadData() {
        for view in scrollView.subviews {
            view.removeFromSuperview()
        }
        highLightCellArray.removeAll()
        installItems()
    }
    
    /// 加载试图
    private func initSubviews() {
        addSubview(scrollView)
        scrollView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: config.contentInsets.left).isActive = true
        scrollView.topAnchor.constraint(equalTo: topAnchor, constant: config.contentInsets.top).isActive = true
        scrollView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -config.contentInsets.right).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -config.contentInsets.bottom).isActive = true
        reloadData()
    }
    
    /// 创建Cell
    private func installItems() {
        let sectionCount = dataSource?.numberOfSections(in: self) ?? 0
        let itemCount = dataSource?.numberOfItems(in: self) ?? 0
        if sectionCount == 0 || itemCount == 0 {
            return
        }
        var lastSectionStackView: UIStackView? = nil
        var sectionCellArray: [[YSSpreadSheetSubView]] = Array(repeating: [], count: itemCount)
        var sectionStackViewArray: [UIStackView] = []
        for section in 0..<sectionCount {
            let sectionStackView = createStackView(at: section, with: lastSectionStackView, with: itemCount)
            sectionStackViewArray.append(sectionStackView)
            for item in 0..<itemCount {
                var cell: YSSpreadSheetSubView? = nil
                if config.isShowItemTitle && section == 0 {
                    cell = dataSource?.spreadSheetView?(self, titleViewForItemAt: item)
                    cell?.indexPath = IndexPath(item: item, section: 0)
                }else if config.isShowSectionTitle && item == 0 {
                    cell = dataSource?.spreadSheetView?(self, titleViewForSectionAt: section)
                    cell?.indexPath = IndexPath(item: 0, section: section)
                }else{
                    cell = cellforItem(at: IndexPath(item: item, section: section))
                    cell?.indexPath = IndexPath(item: item, section: section)
                }
                if let cell = cell {
                    cell.cellDidHighLightBlock = { [weak self] highLightCell, highLight in
                        self?.cellHighLight(highLightCell, highLight: highLight)
                    }
                    cell.viewTapDelegate = delegate
                    sectionStackView.addArrangedSubview(cell)
                    if !config.isAverageSheet {
                        if let cellWidth = dataSource?.spreadSheetView?(self, widthForCellAt: item) {
                            if cellWidth != YSSpreadSheetViewConfig.automaticDimension {
                                cell.widthLayout = cell.widthAnchor.constraint(equalToConstant: cellWidth)
                                cell.widthLayout?.isActive = true
                            }
                        }
                    }else{
                        if config.itemWidth != YSSpreadSheetViewConfig.automaticDimension {
                            cell.widthLayout = cell.widthAnchor.constraint(equalToConstant: config.itemWidth)
                            cell.widthLayout?.isActive = true
                        }else{
                            cell.widthLayout = cell.widthAnchor.constraint(greaterThanOrEqualToConstant: config.estimatedItemWidth)
                            cell.widthLayout?.isActive = true
                        }
                    }
                    if config.isShowLine {
                        cell.lineColor = config.lineColor
                        cell.lineWidth = config.lineWidth
                        if section != sectionCount - 1 && item != itemCount - 1 {
                            cell.position = .leftTop
                        }else if section != sectionCount - 1 && item == itemCount - 1 {
                            cell.position = .leftTopRight
                        }else if section == sectionCount - 1 && item != itemCount - 1 {
                            cell.position = .leftTopBottom
                        }else if section == sectionCount - 1 && item == itemCount - 1 {
                            cell.position = .leftTopRightBottom
                        }
                    }
                    sectionCellArray[item].append(cell)
                }
            }
            lastSectionStackView = sectionStackView
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {[self] in
            /// 宽度
            var largeMaxWidth: CGFloat = -1
            var maxWidth: [CGFloat] = Array(repeating: -1, count: itemCount)
            for (sectionIndex, itemCellArray) in sectionCellArray.enumerated() {
                for cellView in itemCellArray {
                    maxWidth[sectionIndex] = max(maxWidth[sectionIndex], CGRectGetWidth(cellView.frame))
                    largeMaxWidth = max(largeMaxWidth, maxWidth[sectionIndex])
                }
            }
            
            if config.isAverageSheet {
                for itemCellArray in sectionCellArray {
                    for cellView in itemCellArray {
                        cellView.widthLayout?.isActive = false
                        cellView.widthLayout = cellView.widthAnchor.constraint(equalToConstant: largeMaxWidth)
                        cellView.widthLayout?.isActive = true
                    }
                }
            }else{
                for (sectionIndex, itemCellArray) in sectionCellArray.enumerated() {
                    for cellView in itemCellArray {
                        cellView.widthLayout?.isActive = false
                        cellView.widthLayout = cellView.widthAnchor.constraint(equalToConstant: maxWidth[sectionIndex])
                        cellView.widthLayout?.isActive = true
                    }
                }
            }
            
            scrollView.layoutIfNeeded()
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {[self] in
                scrollView.contentSize = CGSize(width: sectionStackViewArray.last!.frame.width, height: CGRectGetMaxY(sectionStackViewArray.last!.frame))
            }
        }
    }
    
    /// 存储/移除高亮的Cell
    /// - Parameters:
    ///   - cell: 操作的Cell
    ///   - highLight: 是否高亮
    private func cellHighLight(_ cell: YSSpreadSheetSubView, highLight: Bool) {
        DispatchQueue.global().async {[self] in
            if highLight {
                highLightCellArray.append(cell)
                if highLightCellArray.count > config.totalHighLightCountInView {
                    DispatchQueue.main.async {[self] in
                        highLightCellArray.first!.isHighLight = false
                    }
                }
                let sectionIndex = cell.indexPath!.section
                let itemIndex = cell.indexPath!.item
                let tempHighLightCellArray = highLightCellArray
                var hightLightCount = 0
                var itemHighLightCount = 0
                let maxSectionHighLightCount = dataSource?.spreadSheetView?(self, sectionHighLightCountIn: sectionIndex) ?? config.totalHighLightCountInSection
                let maxItemHighLightCount = dataSource?.spreadSheetView?(self, itemHighLightCountIn: sectionIndex) ?? config.totalHighLightCountInItem
                for hasHighLightCell in tempHighLightCellArray.reversed() {
                    if hasHighLightCell.indexPath!.section == sectionIndex {
                        hightLightCount += 1
                        if hightLightCount > maxSectionHighLightCount {
                            DispatchQueue.main.async {
                                hasHighLightCell.isHighLight = false
                            }
                            continue
                        }
                    }
                    if hasHighLightCell.indexPath!.item == itemIndex {
                        itemHighLightCount += 1
                        if itemHighLightCount > maxItemHighLightCount {
                            DispatchQueue.main.async {
                                hasHighLightCell.isHighLight = false
                            }
                        }
                    }
                }
            }else{
                DispatchQueue.main.async { [self] in
                    highLightCellArray.removeAll(where: {$0 === cell})
                }
            }
        }
    }
    
    /// 创建StackView
    /// - Parameters:
    ///   - section: 行
    ///   - lastStackView: 上一个StackView
    ///   - itemCount: 列总数
    /// - Returns: 行StackView
    private func createStackView(at section:Int, with lastStackView: UIStackView?, with itemCount: Int) -> UIStackView {
        let sectionStackView = UIStackView()
        sectionStackView.axis = .horizontal
        sectionStackView.spacing = 0
        sectionStackView.backgroundColor = .clear
        sectionStackView.tag = section + 100
        sectionStackView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.addSubview(sectionStackView)
        
        /// 左
        sectionStackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
        /// 宽度
        if config.isAverageSheet {
            sectionStackView.distribution = .fillEqually
            if config.currentShowCount < CGFloat(itemCount) && config.currentShowCount != YSSpreadSheetViewConfig.automaticDimension {
                sectionStackView.widthLayout = sectionStackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: CGFloat(itemCount) / config.currentShowCount)
                sectionStackView.widthLayout?.isActive = true
            }else{
                if config.boundsToView {
                    sectionStackView.widthLayout = sectionStackView.widthAnchor.constraint(greaterThanOrEqualTo: scrollView.widthAnchor)
                    sectionStackView.widthLayout?.isActive = true
                }
            }
        }else{
            if config.boundsToView {
                sectionStackView.widthLayout = sectionStackView.widthAnchor.constraint(greaterThanOrEqualTo: scrollView.widthAnchor)
                sectionStackView.widthLayout?.isActive = true
            }
            sectionStackView.distribution = .fill
        }
        
        /// 高度
        if let sectionHeight = dataSource?.spreadSheetView?(self, heightForCellAt: section) {
            sectionStackView.heightAnchor.constraint(equalToConstant: sectionHeight).isActive = true
        }else if config.sectionHeight == YSSpreadSheetViewConfig.automaticDimension {
            sectionStackView.heightAnchor.constraint(greaterThanOrEqualToConstant: config.estimatedSectionHeight).isActive = true
        }else{
            sectionStackView.heightAnchor.constraint(greaterThanOrEqualToConstant: config.sectionHeight).isActive = true
        }
        
        /// 右
        if let lastStackView = lastStackView {
            sectionStackView.topAnchor.constraint(equalTo: lastStackView.bottomAnchor).isActive = true
        }else{
            sectionStackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
        }
        
        return sectionStackView
    }
}

private var widthLayoutKey : Void?
fileprivate extension UIStackView {
    var widthLayout: NSLayoutConstraint? {
        get {
            return objc_getAssociatedObject(self, &widthLayoutKey) as? NSLayoutConstraint
        }
        
        set {
            objc_setAssociatedObject(self, &widthLayoutKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}
